<?php
use Doctrine\ORM\Mapping\ClassMetadataInfo,
    Doctrine\ORM\Mapping\AssociationMapping,
    Doctrine\Common\Util\Inflector,
    Doctrine\ORM\Tools\EntityGenerator,
    Doctrine\ORM\Tools\DisconnectedClassMetadataFactory,
	Doctrine\ORM\Tools;

class App_Service_Doctrine
{
	private $xmldir;
	
	public function __construct()
	{
		$this->xmldir = APPLICATION_PATH . "/../xmldriver/";
	}
	
	public function getAllEntites()
	{
		$ents = array();
		$files = scandir($this->xmldir);
		foreach ($files as $f){
			if($f === '.' || $f === '..' || substr($f, 0, 1) === '.') {continue;} 
			
			$entity = simplexml_load_file($this->xmldir . $f);
			$entAttrs = $entity->entity->attributes();			
			$ents[] = array(
				'name'=>(string)$entAttrs['name'],
				'displayname'=>(string)$entAttrs['displayname']				
			);
		}
		return $ents;		
	}
	
	public function createEntityXml($name, $displayname)
	{		
		$entityname = $this->getModelNamePrefix() . $name;
		$table = Zend_Auth::getInstance()->getIdentity()->company . "_" . $name;
		if ($displayname == '') {
			$displayname = $name;
		}
		
		$data = "
<doctrine-mapping xmlns='http://doctrine-project.org/schemas/orm/doctrine-mapping'
      xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
      xsi:schemaLocation='http://doctrine-project.org/schemas/orm/doctrine-mapping
                          http://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd'>
    <entity name='{$entityname}' table='{$table}' displayname='{$displayname}'>
        <id name='id' type='integer' column='id'>
            <generator strategy='AUTO'/>            
        </id>        
    </entity>
</doctrine-mapping>
		";	
		return file_put_contents($this->xmldir . $entityname . ".dcm.xml", $data);
	}
	
	public function deleteEntity($name)
	{
		$company = Zend_Auth::getInstance()->getIdentity()->company;
		//remove xml
		unlink($this->xmldir .$name . ".dcm.xml");
		
		$ns = explode("_", $name);
		//remove php
		unlink(APPLICATION_PATH . "/models/{$company}/" . $ns[3] . ".php");
		
		//drop table
		$db = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getPluginResource('db')->getDbAdapter();
		$table = $company . "_" . $ns[3];
		$db->query("drop table if EXISTS " . $table);
		
		//remove relation
		$files = scandir($this->xmldir);
		foreach ($files as $f)
		{
			if($f === '.' || $f === '..' || substr($f, 0, 1) === '.') {continue;} 
			
			$entity = simplexml_load_file($this->xmldir . $f);
			foreach ($entity->entity->children() as $ef)
			{
				$fattrs = $ef->attributes();
				if ((string)$fattrs['target-entity'] == "target-entity") {
					unset($ef);
				}
			}	

			$entity->asXML($this->xmldir . $f);
		}				
	}
	
	public function getEntityFields($entityname)
	{
		$entity = simplexml_load_file($this->xmldir  .$entityname . ".dcm.xml");
		$fields = array();
		foreach ($entity->entity->field as $field){
			$fieldAttrs = $field->attributes();			
			$fields[] = array(
				'name'=>(string)$fieldAttrs['name'],
				'oname'=>(string)$fieldAttrs['name'],
				'type'=>(string)$fieldAttrs['type'],
				'column'=>(string)$fieldAttrs['column'],
				'length'=>(int)$fieldAttrs['length'],
				'unique'=>(bool)$fieldAttrs['unique'],
				'nullable'=>(bool)$fieldAttrs['nullable'],				
				'precision'=>(int)$fieldAttrs['precision'],
				'column-definition'=>(string)$fieldAttrs['column-definition'],
			);
		}
		return $fields;	
	}
	
	public function getMany2One($entityname)
	{
		$entity = simplexml_load_file($this->xmldir  .$entityname . ".dcm.xml");
		$many2one = array();
		foreach ($entity->entity->children() as $m2o){
			if ($m2o->getName() !== "many-to-one") {
				continue;
			}
			$m2oAttrs = $m2o->attributes();			
			$many2one[] = array(
				'field'=>(string)$m2oAttrs['field'],
				'oname'=>(string)$m2oAttrs['field'],
				'target-entity'=>(string)$m2oAttrs['target-entity'],
				//'inversed-by'=>(string)$m2oAttrs['inversed-by']
			);
		}
		return $many2one;	
	}
	
	public function getMany2Many($entityname)
	{
		$entity = simplexml_load_file($this->xmldir  .$entityname . ".dcm.xml");
		$many2many = array();
		foreach ($entity->entity->children() as $m2o){
			if ($m2o->getName() !== "many-to-many") {
				continue;
			}
			$m2oAttrs = $m2o->attributes();			
			$many2many[] = array(
				'field'=>(string)$m2oAttrs['field'],
				'oname'=>(string)$m2oAttrs['field'],
				'target-entity'=>(string)$m2oAttrs['target-entity'],
				//'inversed-by'=>(string)$m2oAttrs['inversed-by']
			);
		}
		return $many2many;		
	}
	
	public function updateEntityField($entityname, $field)
	{
		$xml = simplexml_load_file($this->xmldir  . $entityname . ".dcm.xml");
		
		//add field
		if ($field['oname'] == '') {
			$entity = $xml->entity;
			$f = $entity->addChild('field');
			
			$f->addAttribute('name', $field['name']);
			$f->addAttribute('type', $field['type']);
		}
		//edit
		else {
			$entity = $xml->entity;
			foreach ($entity->field as $f){
				$fattr = $f->attributes();
				if ((string)$fattr['name'] == $field['oname']) {
					$fattr['name']= $field['name'];
					$fattr['type']= $field['type'];
					$fattr['nullable']= $field['nullable'];
				}
			}
		}
		
		$xml->asXML($this->xmldir . $entityname . ".dcm.xml");
		
		return true;
	}
	
	public function updateMany2One($entityname, $field)
	{
		$xml = simplexml_load_file($this->xmldir  . $entityname . ".dcm.xml");
		
		//add
		if ($field['oname'] == '') {
			$entity = $xml->entity;
			$f = $entity->addChild('many-to-one');
			
			$f->addAttribute('field', $field['field']);
			$f->addAttribute('target-entity', $field['target-entity']);
			//$f->addAttribute('inversed-by', $field['inversed-by']);
		}
		//edit
		else {
			$entity = $xml->entity;
			foreach ($entity->entity->children() as $f){
				if ($f->getName() !== "many-to-one") {
					continue;
				}
				
				$fattr = $f->attributes();
				if ((string)$fattr['field'] == $field['oname']) {
					$fattr['field']= $field['field'];
					$fattr['target-entity']= $field['target-entity'];
					//$fattr['inversed-by']= $field['inversed-by'];
				}				
			}			
		}
		
		$xml->asXML($this->xmldir . $entityname . ".dcm.xml");
		
		return true;
	}
	public function updateMany2Many($entityname, $field)
	{
		$xml = simplexml_load_file($this->xmldir  . $entityname . ".dcm.xml");
		
		//add
		if ($field['oname'] == '') {
			$entity = $xml->entity;
			$f = $entity->addChild('many-to-many');
			
			$f->addAttribute('field', $field['field']);
			$f->addAttribute('target-entity', $field['target-entity']);
			//$f->addAttribute('inversed-by', $field['inversed-by']);
		}
		//edit
		else {
			$entity = $xml->entity;
			foreach ($entity->entity->children() as $f){
				if ($f->getName() !== "many-to-many") {
					continue;
				}
				
				$fattr = $f->attributes();
				if ((string)$fattr['field'] == $field['oname']) {
					$fattr['field']= $field['field'];
					$fattr['target-entity']= $field['target-entity'];
					//$fattr['inversed-by']= $field['inversed-by'];
				}				
			}			
		}
		
		$xml->asXML($this->xmldir . $entityname . ".dcm.xml");
		
		return true;
	}
	public function removeEntityField($entityname, $field)
	{
		$xml = simplexml_load_file($this->xmldir . $entityname . ".dcm.xml");			
		
		$entity = $xml->entity;
		foreach ($entity->field as $f){
			$fattr = $f->attributes();
			if ((string)$fattr['name'] == $field['name']) {				
				$dom=dom_import_simplexml($f);
				$dom->parentNode->removeChild($dom);
				break;
			}
		}
		$xml->asXML($this->xmldir . $entityname . ".dcm.xml");	
		return true;
		
	}
	
	public function removeMany2One($entityname, $field)
	{
		$xml = simplexml_load_file($this->xmldir .  $entityname . ".dcm.xml");	
				
		$entity = $xml->entity;
		foreach ($entity->entity->children() as $f){
			if ($f->getName() !== "many-to-one") {
				continue;
			}
			$fattr = $f->attributes();
			if ((string)$fattr['field'] == $field['field']) {
				$dom=dom_import_simplexml($f);
				$dom->parentNode->removeChild($dom);
				break;
			}
		}
		
		$xml->asXML($this->xmldir . $entityname . ".dcm.xml");
		return true;
	}
	public function removeMany2Many($entityname, $field)
	{
		$xml = simplexml_load_file($this->xmldir .  $entityname . ".dcm.xml");	
				
		$entity = $xml->entity;
		
		foreach ($entity->children() as $f)
		{			
			if ($f->getName() !== "many-to-many") {
				continue;
			}
			$fattr = $f->attributes();
			if ((string)$fattr['field'] == $field['field']) {
				$dom=dom_import_simplexml($f);
				$dom->parentNode->removeChild($dom);
				break;
			}
		}
		
		$xml->asXML($this->xmldir . $entityname . ".dcm.xml");
		return true;
	}
	public function runModeling()
	{
		$company = Zend_Auth::getInstance()->getIdentity()->company;
		
		$registry = Zend_Registry::getInstance();	
		$em = $registry->entityManager;
		
		//generate entities
        $cmf = new DisconnectedClassMetadataFactory();
        $cmf->setEntityManager($em);
        $metadatas = $cmf->getAllMetadata();
        //$metadatas = MetadataFilter::filter($metadatas, $input->getOption('filter'));
        if (count($metadatas)) {
        	$entityGenerator = new EntityGenerator();
        
        	$entityGenerator->setGenerateAnnotations(false);
        	$entityGenerator->setGenerateStubMethods(true);
        	$entityGenerator->setRegenerateEntityIfExists(true);
        	$entityGenerator->setUpdateEntityIfExists(false);
        	$entityGenerator->setNumSpaces(4);
        	$entityGenerator->setClassToExtend("ZendX_Model_Base");
        	$entityGenerator->generate($metadatas, APPLICATION_PATH . "/../models/{$company}/");	
        }       
        
		//update schema		
		$metadatas = $em->getMetadataFactory()->getAllMetadata();

        if ( ! empty($metadatas)) {
            // Create SchemaTool
            $tool = new \Doctrine\ORM\Tools\SchemaTool($em);
            $tool->updateSchema($metadatas, true);
        }       
        
		return true;
	}
	
	public static function getModelNamePrefix()
	{
		$appnamespace = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getAppNamespace();
		$company = Zend_Auth::getInstance()->getIdentity()->company;
		return $company . "_";//$appnamespace . "_Model_" . $company . "_";
	}
	
}